from io import BytesIO

from PIL import Image, ImageDraw, ImageFont
from blog.models import Post
from django.conf import settings
from django.contrib import messages
from django.contrib.auth import get_user_model
from django.contrib.auth import views as auth_views
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse, Http404
from django.shortcuts import render, redirect, reverse
from django.urls import reverse_lazy
from django_redis import get_redis_connection
from itsdangerous import (
    TimedJSONWebSignatureSerializer as Serializer,
    SignatureExpired,
    BadSignature
)

from .forms import (
    RegistrationForm,
    UserUpdateForm,
    ProfileForm,
    CustomPasswordResetForm,
    CustomAuthenticationForm,
)

User = get_user_model()


# 密码重置不需要登录，如果用户输入的邮箱对应的用户不存在，应该提醒该用户不存在
class PasswordResetView(auth_views.PasswordResetView):
    """密码重置视图，显示邮箱输入框"""
    form_class = CustomPasswordResetForm
    success_url = reverse_lazy('account:password_reset_done')
    template_name = 'account/password_reset_form.html'
    email_template_name = 'account/password_reset_email.html'


class PasswordResetConfirmView(auth_views.PasswordResetConfirmView):
    """密码重置链接，含有令牌(token)，显示重置密码输入框"""
    success_url = reverse_lazy('account:password_reset_complete')
    template_name = 'account/password_reset_confirm.html'


class PasswordChangeView(auth_views.PasswordChangeView):
    """更改密码页面"""
    success_url = reverse_lazy('account:password_change_done')
    template_name = 'account/password_change_form.html'


def register(request):
    """用户注册视图"""

    # 如果用戶已经登录，直接访问注册页面(/account/register/)则重定向到主页面
    if request.user.is_authenticated:
        return redirect(reverse('blog:index'))

    form = RegistrationForm()
    if request.method == 'POST':
        form = RegistrationForm(request.POST)
        if form.is_valid():
            user = form.save()
            try:
                user.send_active_mail()  # 发送激活邮箱
            except Exception:
                # logging?? 未启动邮箱服务
                pass
            else:
                messages.success(
                    request,
                    f'激活邮件已经发送至{form.cleaned_data["email"]}，请查看邮件并根据指示激活您的账户'
                )
                return redirect(reverse('account:login'))

    context = {'form': form}
    return render(request, 'account/register.html', context)


# 如果用户没有登录，重定向到settings.LOGIN_URL
@login_required
def profile(request):
    """用户个人中心页面"""
    # instance关键字参数，填充原来的值
    user_form = UserUpdateForm(instance=request.user)
    profile_form = ProfileForm(instance=request.user.profile)

    if request.method == 'POST':
        user_form = UserUpdateForm(request.POST, instance=request.user)
        profile_form = ProfileForm(request.POST, request.FILES, instance=request.user.profile)
        if user_form.is_valid() and profile_form.is_valid():
            user_form.save()
            profile_form.save()
            messages.success(request, '个人信息更新成功')
            return redirect(reverse('account:profile'))

    context = {
        'user_form': user_form,
        'profile_form': profile_form,
    }

    return render(request, 'account/profile.html', context)


def verify_code(request):
    """生成认证码图片响应给前端页面"""
    import random
    # RGB
    bgcolor = (random.randrange(20, 100), random.randrange(20, 100), 255)
    width = 128
    height = 37
    # 画布
    im = Image.new('RGB', (width, height), bgcolor)
    # 画笔
    draw = ImageDraw.Draw(im)
    # 画两百个噪点
    for _ in range(200):
        # 位置
        xy = (random.randrange(0, width), random.randrange(0, height))
        # 颜色
        fill = (random.randrange(0, 255), 255, random.randrange(0, 255))
        draw.point(xy, fill)

    # 选4个值为验证码
    allowed_chars = 'abcdefghijkmnpqrstuvwxyz23456789'
    random_chars = random.choices(allowed_chars, k=4)  # list

    # 字体
    font = ImageFont.truetype('FreeMono.ttf', 23)
    # 字体颜色
    font_color = (255, random.randrange(0, 255), random.randrange(0, 255))
    # 绘制
    draw.text((5, 2), random_chars[0], font=font, fill=font_color)
    draw.text((25, 2), random_chars[1], font=font, fill=font_color)
    draw.text((50, 2), random_chars[2], font=font, fill=font_color)
    draw.text((75, 2), random_chars[3], font=font, fill=font_color)
    # 释放画笔
    del draw

    # 存入session，存入的是字符串 (需要session表，python manage.py migrate)
    request.session['verify_code'] = ''.join(random_chars)
    # 内存文件操作
    buf = BytesIO()
    # 将图片保存在内存中，文件类型为png
    im.save(buf, 'png')
    # 返回给用户，MIME类型为PNG
    return HttpResponse(buf.getvalue(), 'image/png')


class LoginView(auth_views.LoginView):
    form_class = CustomAuthenticationForm


def activate_user_account(request, token):
    """进行用户激活"""

    # 进行解密，获取要激活的哟用户信息
    serializer = Serializer(settings.SECRET_KEY, settings.TOKEN_EXPIRES)
    try:
        data = serializer.loads(token)
        # 获取待激活的用户id
        user_id = data['user_id']

        try:
            user = User.objects.get(id=user_id)
        except User.DoesNotExists:
            raise Http404('用户不存在')
        else:
            # 如果账号已经激活不需要保存第二次
            if not user.is_active:
                user.is_active = True
                user.save()

        messages.success(request, '账号激活成功，请登录')
        # 跳转到登陆页面
        return redirect(reverse('account:login'))

    except (SignatureExpired, BadSignature):
        raise Http404('激活码失效')
